using System;
using Jink.Core.Converters.Annotations;
using XenoGears.Assertions;
using XenoGears.Reflection;
using XenoGears.Reflection.Generics;
using XenoGears.Reflection.Shortcuts;
using System.Linq;

namespace Jink.Core.Converters.Default
{
    // todo. implement more conversions

    [Converter]
    internal static class CSharpConversions
    {
        [Converter(Weight = 1)]
        public static D ReferenceConversion<S, D>(S obj)
        {
            typeof(D).IsAssignableFrom(typeof(S)).AssertTrue();
            return (D)(Object)obj;
        }

        [Converter(Weight = 1)]
        public static D ImplicitConversion<S, D>(S obj)
        {
            var s_imps = typeof(S).GetMethods(BF.PublicStatic).Where(m => m.Name == "op_Implicit");
            var d_imps = typeof(D).GetMethods(BF.PublicStatic).Where(m => m.Name == "op_Implicit");
            var cast = s_imps.Concat(d_imps).AssertSingle(m => m.Param(0) == typeof(S) && m.Ret() == typeof(D));
            return (D)cast.Invoke(null, new Object[]{obj});
        }

        [Converter(Weight = 1)]
        public static D ExplicitConversion<S, D>(S obj)
        {
            var s_imps = typeof(S).GetMethods(BF.PublicStatic).Where(m => m.Name == "op_Explicit");
            var d_imps = typeof(D).GetMethods(BF.PublicStatic).Where(m => m.Name == "op_Explicit");
            var cast = s_imps.Concat(d_imps).AssertSingle(m => m.Param(0) == typeof(S) && m.Ret() == typeof(D));
            return (D)cast.Invoke(null, new Object[] { obj });
        }
    }
}